//
// Copyright (c) 2006, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
//   4 Jan 06  Brian Frank  Creation
//

**
** Slot represents a member field or method on a Type.
**
native abstract rtconst class Slot
{
  private Type _parent
  private const Str _name
  private const Str? _doc
  private const Int _flags

  private FacetList _facets := FacetList()

//////////////////////////////////////////////////////////////////////////
// Management
//////////////////////////////////////////////////////////////////////////

  **
  ** Find a Slot by it's qualified name "pod::Type.slot".  If the slot
  ** doesn't exist and checked is false then return null, otherwise
  ** throw UnknownSlotErr.
  **
  static Slot? find(Str qname, Bool checked := true) {
    dot := qname.indexr(".")
    typeName := qname[0 ..< dot]
    slotName := qname[dot + 1 ..-1]

    type := Type.find(typeName, checked);
    if (type == null)
      return null

    return type.slot(slotName, checked)
  }

  **
  ** Convenience for '(Method)find(qname, checked)'
  **
  static Method? findMethod(Str qname, Bool checked := true) {
    return (Method) find(qname, true)
  }

  **
  ** Convenience for '(Field)find(qname, checked)'
  **
  static Field? findField(Str qname, Bool checked := true) {
    return (Field) find(qname, true);
  }

  **
  ** Convenience for 'findMethod(qname, checked).func'
  **
  static Func? findFunc(Str qname, Bool checked := true) {
    findMethod(qname, checked).func
  }

//////////////////////////////////////////////////////////////////////////
// Constructor
//////////////////////////////////////////////////////////////////////////

  **
  ** Internal constructor.
  **
  internal new make(Type parent, Str name, Str? doc, Int flags) {
    _parent = parent
    _name = name
    _doc = doc
    _flags = flags
  }

//////////////////////////////////////////////////////////////////////////
// Naming
//////////////////////////////////////////////////////////////////////////

  **
  ** Parent type which defines this slot.
  **
  Type parent() { _parent }

  **
  ** Simple name of the slot such as "size".
  **
  Str name() { _name }

  **
  ** Qualified name such as "sys:Str.size".
  **
  Str qname() { parent.qname + "." + name }

  **
  ** Return true if this is an instance of Field.
  **
  Bool isField() { this is Field }

  **
  ** Return true if this is an instance of Method.
  **
  Bool isMethod() { this is Method }

//////////////////////////////////////////////////////////////////////////
// Flags
//////////////////////////////////////////////////////////////////////////

  private Int flags() { _flags }

  **
  ** Return if slot is abstract (no implementation provided).
  **
  Bool isAbstract() { flags.and(ConstFlags.Abstract) != 0 }

  **
  ** Return if slot is constant and thread safe.  A constant field
  ** is explicitly marked with the const modifier and guaranteed
  ** to always reference the same immutable object for the life of
  ** the VM.  A const method is guaranteed to not capture any
  ** state from its thread, and is safe to execute on other threads.
  ** The compiler marks methods as const based on the following
  ** analysis:
  **   - static methods are always automatically const
  **   - instance methods are never const
  **   - closures which don't capture any variables from their
  **     scope are automatically const
  **   - partional apply methods which only capture const variables
  **     from their scope are automatically const
  **
  Bool isConst() { flags.and(ConstFlags.Const) != 0 }

  **
  ** Return if slot is constructor method.
  **
  Bool isCtor() { flags.and(ConstFlags.Ctor) != 0 }

  **
  ** Return if slot has internal protection scope.
  **
  Bool isInternal() { flags.and(ConstFlags.Internal) != 0 }

  **
  ** Return if slot is native.
  **
  Bool isNative() { flags.and(ConstFlags.Native) != 0 }

  **
  ** Return if slot is an override (of parent's virtual method).
  **
  Bool isOverride() { flags.and(ConstFlags.Override) != 0 }

  **
  ** Return if slot has private protection scope.
  **
  Bool isPrivate() { flags.and(ConstFlags.Private) != 0 }

  **
  ** Return if slot has protected protection scope.
  **
  Bool isProtected() { flags.and(ConstFlags.Protected) != 0 }

  **
  ** Return if slot has public protection scope.
  **
  Bool isPublic() { flags.and(ConstFlags.Public) != 0 }

  **
  ** Return if slot is static (class based, rather than instance).
  **
  Bool isStatic() { flags.and(ConstFlags.Static) != 0 }

  **
  ** Return if this slot was generated by the compiler.
  **
  Bool isSynthetic() { flags.and(ConstFlags.Synthetic) != 0 }

  **
  ** Return if slot is virtual (may be overridden in subclasses).
  **
  Bool isVirtual() { flags.and(ConstFlags.Virtual) != 0 }

//////////////////////////////////////////////////////////////////////////
// Facets
//////////////////////////////////////////////////////////////////////////

  internal Void addFacet(Str type, Str val) {
    _facets.addFacet(type, val)
  }

  **
  ** Get the list of facets defined on this slot or return an empty
  ** list if no facets are defined. If looking up a facet by type, then
  ** use the `facet` method which will provide better performance.
  ** See [Facets Doc]`docLang::Facets` for details.
  **
  Facet[] facets() { _facets.facets }

  **
  ** Get a facet by its type.  If not found on this slot then
  ** return null or throw UnknownFacetErr based on check flag.
  ** See [Facets Doc]`docLang::Facets` for details.
  **
  Facet? facet(Type type, Bool checked := true) {
    _facets.getFacet(type, checked)
  }

  **
  ** Return if this type has the specified facet defined.
  **
  Bool hasFacet(Type type) {
    facet(type, false) != null
  }

//////////////////////////////////////////////////////////////////////////
// Documentation
//////////////////////////////////////////////////////////////////////////

  **
  ** Return the raw fandoc for this slot or null if not available.
  **
  Str? doc() { _doc }

//////////////////////////////////////////////////////////////////////////
// Conversion
//////////////////////////////////////////////////////////////////////////

  **
  ** Always return qname().
  **
  override Str toStr() { qname }

  **
  ** Return a string representation of the Fantom code signature.
  **
  abstract Str signature()


  override Bool isImmutable() {
    true
  }

  override Obj toImmutable() {
    this
  }
}